package com.rosiminc.pm.model;

import java.util.Observable;

import com.rosiminc.pm.game.*;

/**
 * This model encapsulates a PipesMania game instance.
 * 
 * @author Shymon
 * 
 */
public class PipesManiaGameModel extends Observable {

	private PipesManiaGame game;
	private static final int DEFAULT_SIZE = 10;

	/**
	 * This constructor creates a game with default size.
	 */
	public PipesManiaGameModel() {
		this(DEFAULT_SIZE, DEFAULT_SIZE);
	}

	/**
	 * This constructor creates a game with specified number of rows and
	 * columns.
	 * 
	 * @param rows
	 *            number of rows
	 * @param cols
	 *            number of columns
	 */
	public PipesManiaGameModel(int rows, int cols) {
		game = new PipesManiaGame(rows, cols);
	}

	/**
	 * This constructor creates a game with specified options.
	 * 
	 * @param options
	 *            the game options
	 */
	public PipesManiaGameModel(PipesManiaOptions options) {
		game = new PipesManiaGame(options);
	}

	/**
	 * This method retrieves the game's options.
	 * 
	 * @return the game options
	 */
	public PipesManiaOptions getGameOptions() {
		return game.getGameOptions();
	}

	/**
	 * This method sets the game's options.
	 * 
	 * @param options
	 *            the game options
	 */
	public void setGameOptions(PipesManiaOptions options) {
		game.setGameOptions(options);
	}

	/**
	 * This method starts a new game.
	 */
	public void newGame() {
		game.newGame();
		alertObservers(getBoard());
		checkIfOver();
	}

	/**
	 * This method shuffles the board tiles.
	 */
	public void shuffleTiles() {
		game.shuffleTiles();
		alertObservers(getBoard());
	}

	/**
	 * This method alerts the observers if the game is won.
	 */
	public void checkIfOver() {
		if (game.isWon())
			alertObservers();
	}

	/**
	 * This method returns the board of game tiles.
	 * 
	 * @return the game board
	 */
	private PipesManiaTileModel[][] getBoard() {
		PipesManiaOptions options = game.getGameOptions();
		int numRows = options.getNumRows();
		int numCols = options.getNumCols();
		PipesManiaTileModel[][] board = new PipesManiaTileModel[numRows][numCols];
		for (int i = 0; i < numRows; i++)
			for (int j = 0; j < numCols; j++)
				board[i][j] = new PipesManiaTileModel(game.getGameBoardTileAt(
						i, j), this);

		return board;
	}

	/**
	 * This method performs the primary action of a given tile.
	 * 
	 * @param row
	 *            the row
	 * @param col
	 *            the column
	 */
	public void actionA(int row, int col) {
		game.performActionA(row, col);
	}

	/**
	 * This method performs the secondary action of a given tile.
	 * 
	 * @param row
	 *            the row
	 * @param col
	 *            the column
	 */
	public void actionB(int row, int col) {
		game.performActionB(row, col);
	}

	/**
	 * This method alerts the observers.
	 */
	private void alertObservers() {
		alertObservers(null);
	}

	/**
	 * This method alerts the observers with a specified signal.
	 * 
	 * @param o
	 *            the signal
	 */
	private void alertObservers(Object o) {
		setChanged();
		notifyObservers(o);
	}
}
